package com.inspectortime.webapp.util;

import java.io.Serializable;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpSession;

import org.springframework.util.StringUtils;

import com.inspectortime.domain.Employee;
import com.inspectortime.domain.Inspection;
import com.inspectortime.domain.InspectorCompany;
import com.inspectortime.domain.User;
import com.inspectortime.repository.Repository;

/**
 * Consolidates all interractions and attribute keys used with the HttpSession
 * 
 * @author mkvalsvik
 * 
 */
public class HttpSessionUtils {

	private HttpSessionUtils() {
	}

	public static final String SESSION_ATTRIBUTE_FROM_SEARCH_FLAG = "fromSearch";
	public static final String SESSION_ATTRIBUTE_USER_ID = "userId";
	public static final String SESSION_ATTRIBUTE_USERNAME = "userName";
	public static final String SESSION_ATTRIBUTE_INSPECTION_ID = "inspectionId";

	public static void removeLoggedInUser(HttpServletRequest request) {
		request.getSession().setAttribute(SESSION_ATTRIBUTE_USER_ID, null);
		request.getSession().setAttribute(SESSION_ATTRIBUTE_USERNAME, null);
	}
	
	/**
	 * Used during login as a workaround for frequent timeout bug
	 * @param request
	 */
	public static void invalidateExistingSession(HttpServletRequest request) {
		HttpSession session = request.getSession(false);
		if (session != null) {
			session.invalidate();
		}
	}
	
	public static void storeLoggedInUser(HttpServletRequest request, User user) {
		request.getSession().setAttribute(SESSION_ATTRIBUTE_USER_ID, user.getId());
		request.getSession().setAttribute(SESSION_ATTRIBUTE_USERNAME, user.getUserName());
	}
	
	public static boolean isUserLoggedIn(HttpServletRequest request) throws LoggedInUserNotFoundException {
		HttpSession session = request.getSession(false);
		if (session == null) {
			return false;
		}
		Serializable userId = (Serializable) session.getAttribute(
				SESSION_ATTRIBUTE_USER_ID);
		if (userId == null) {
			return false;
		}
		return true;
	}
	
	public static void enableFromSearchFlag(HttpServletRequest request) {
		request.getSession().setAttribute(SESSION_ATTRIBUTE_FROM_SEARCH_FLAG, "true");
	}
	
	public static void disableFromSearchFlag(HttpServletRequest request) {
		request.getSession().setAttribute(SESSION_ATTRIBUTE_FROM_SEARCH_FLAG, null);
	}
	
	public static boolean isEnabledFromSearchFlag(HttpServletRequest request) {
		String s = (String) request.getSession().getAttribute(SESSION_ATTRIBUTE_FROM_SEARCH_FLAG);
		if (StringUtils.hasText(s)
				&& Boolean.valueOf(s)) {
			return true;
		}
		return false;
	}
	
	public static Serializable retrieveLoggedInUserId(HttpServletRequest request) throws LoggedInUserNotFoundException {
		Serializable userId = (Serializable) request.getSession().getAttribute(
				SESSION_ATTRIBUTE_USER_ID);
		if (userId == null) {
			throw new LoggedInUserNotFoundException(
					"Logged in user not found in http session.");
		}
		return userId;
	}
	
	/**
	 * Retrieve user from session and then re-load that user to ensure he is
	 * properly bound to Hibernate session
	 * 
	 * TODO: Consider if there are efficiencies to be gained by merging with
	 * current session instead of re-loading
	 */
	public static User retrieveLoggedInUser(
			HttpServletRequest request, Repository repository)
			throws LoggedInUserNotFoundException {
		User freshUser = repository.loadUser(retrieveLoggedInUserId(request));
		if (freshUser == null) {
			throw new LoggedInUserNotFoundException(
					"User in http session was not found in database.");
		}
		return freshUser;
	}
	
	/*
	public static Inspector retrieveLoggedInInspector(
			HttpServletRequest request, Repository repository)
	throws LoggedInUserNotFoundException {
		User user = HttpSessionUtils.retrieveLoggedInUser(request, repository);
		if (!(user instanceof Inspector)) {
			throw new LoggedInUserNotFoundException("Logged user is not an inspector, operation not allowed.");
		}
		Inspector inspector = (Inspector) user;
		return inspector;
	}
	*/
	
	public static Employee retrieveLoggedInEmployee(
			HttpServletRequest request, Repository repository)
	throws LoggedInUserNotFoundException {
		User user = HttpSessionUtils.retrieveLoggedInUser(request, repository);
		if (!(user instanceof Employee)) {
			throw new LoggedInUserNotFoundException("Logged user is not an employee, operation not allowed.");
		}
		return (Employee) user;
	}
	
	/**
	 * Gets the company associated with the logged in user
	 * @param request
	 * @param repository
	 * @return
	 * @throws LoggedInUserNotFoundException
	 */
	public static InspectorCompany retrieveLoggedInCompany(
			HttpServletRequest request, Repository repository)
	throws LoggedInUserNotFoundException {
		User user = HttpSessionUtils.retrieveLoggedInUser(request, repository);
		if (!(user instanceof Employee)) {
			throw new LoggedInUserNotFoundException("Logged user is not an employee, operation not allowed.");
		}
		return ((Employee) user).getCompany();
	}
	
	/**
	 * Stores the inspectionId of an inspection being created/edited in the inspection wizard
	 * 
	 * @param request
	 * @param inspectionId
	 */
	public static void storeWizardInspection(HttpServletRequest request, Serializable inspectionId) {
		request.getSession().setAttribute(SESSION_ATTRIBUTE_INSPECTION_ID, inspectionId);
	}
	
	/**
	 * Returns the in-progress Inspection from the Session for use in the Wizard
	 * or null if no inspection exists
	 * 
	 * @param request
	 * @param repository
	 */
	public static Inspection retrieveWizardInspection(HttpServletRequest request, Repository repository) throws ExpiredInspectionException {
		Inspection inspection = null;
		String inspectionId = (String) request.getSession().getAttribute(SESSION_ATTRIBUTE_INSPECTION_ID);
		if (!StringUtils.hasText(inspectionId)) {
			throw new ExpiredInspectionException();
		}
		return repository.loadInspection(inspectionId);
	}
	
	/**
	 * Removes the Inspection being edited in the Wizard from the Session
	 * @param request
	 */
	public static void clearWizardInspection(HttpServletRequest request) {
		request.getSession().setAttribute(SESSION_ATTRIBUTE_INSPECTION_ID, null);
	}
	
	public static boolean isWizardInspectionInSession(HttpServletRequest request) {
		return request.getSession().getAttribute(SESSION_ATTRIBUTE_INSPECTION_ID) != null;
	}

}
